package com.softdev.service.impl;

import com.softdev.common.CustomException;
import com.softdev.common.R;
import com.softdev.common.mapper.UserDtoMapper;
import com.softdev.dto.UserDto;
import com.softdev.pojo.Role;
import com.softdev.pojo.Skill;
import com.softdev.pojo.User;
import com.softdev.repo.RoleRepository;
import com.softdev.repo.SkillRepository;
import com.softdev.repo.UserRepository;
import com.softdev.service.UserService;
import com.softdev.utils.DataUtils;
import com.softdev.utils.JwtTokenUtil;
import com.softdev.utils.UserIdFindingUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.*;

@Service
@Slf4j
public class UserServiceImpl implements UserService {

    @Resource
    private AuthenticationManager authenticationManager;

    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private UserRepository userRepository;

    @Resource
    private RoleRepository roleRepository;

    @Resource
    private SkillRepository skillRepository;

    @Resource
    private BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    public String login(String username , String password, HttpServletRequest request) {
        String token = null;
        try {
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username , password);

            Authentication authenticate = authenticationManager.authenticate(authenticationToken);
            User user = (User) authenticate.getPrincipal();

            Claims claims = Jwts.claims();
            claims.put("id" , user.getId());
            claims.put("username" , user.getUsername());
            claims.put("role" , user.getRoles());

            token = jwtTokenUtil.createToken(claims);
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}" ,  e.getMessage());
        }
        return token;
    }
    @Override
    public R<String> logout(HttpServletRequest request, HttpServletResponse response) {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();
        if (auth != null){
            new SecurityContextLogoutHandler().logout(request, response, auth);
        }
        return R.success("退出成功！");
    }

    @Override
    public User get() {

        Long userId = UserIdFindingUtil.getUserId();

        return userRepository.findByIdWithRoles(userId);

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(User user) {

        Long userId = UserIdFindingUtil.getUserId();
        if (!userId.equals(user.getId())) {
            throw new CustomException("只能修改自己的个人信息哦！");
        }

        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));

        userRepository.save(user);

        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean add(UserDto userDto) {

        User user = UserDtoMapper.INSTANCE.UserDtoToUser(userDto);
        user.setPassword(bCryptPasswordEncoder.encode("123"));
        user.setEnabled(true);
        user.setAccountNonExpired(true);
        user.setAccountNonLocked(true);
        user.setCredentialsNonExpired(true);

        List<Role> roles = new ArrayList<>();
        Role role = roleRepository.findByName("ROLE_employee");
        roles.add(role);
        user.setRoles(roles);

        List<Skill> skills = skillRepository.findAllById(Arrays.asList(userDto.getSkillIds()));
        user.setSkills(skills);

        userRepository.save(user);

        return true;
    }

    @Override
    public Page<User> page(int page, int size, Long[] skillIds) {

        List<User> users = userRepository.findAllWithRoles();
        users.removeIf(user -> user.getRoles().size() > 1);

        if (null != skillIds && skillIds.length > 0) {

            List<Skill> skills = skillRepository.findAllById(Arrays.asList(skillIds));

            for (User user : users) {
                List<Skill> userSkills = user.getSkills();
                if (!new HashSet<>(userSkills).containsAll(skills)) {
                    users.remove(user);
                }
            }
        }

        return DataUtils.listToPage(users , page - 1 , size);
    }
}
